package com.sailing.xjpb.orm.query.impl;

import com.sailing.xjpb.common.SailingAssert;
import com.sailing.xjpb.orm.query.ConditionUnit;
import com.sailing.xjpb.orm.query.QueryCondition;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Pageable;

import java.util.List;
import java.util.function.Supplier;

/**
 * 查询条件构建器
 *
 * @author YaoWei
 * createDate: 2020/12/17
 * @see {@link QueryCondition}
 * @see {@link com.sailing.xjpb.orm.query.impl.QueryConditionImpl}
 */
@Data
public final class QueryConditionBuilder {
    /**
     * 排序字段
     */
    private String orderBy;
    /**
     * 分组字段
     */
    private String groupBy;
    /**
     * 分页信息
     */
    private Pageable pageable;
    /**
     * 主查询条件
     */
    private String select;
    /**
     * where条件部分初始化
     * </p>
     * 示例1： name='张三' and age=20
     * </p>
     * 示例2：where name='张三' and age=20
     */
    private String where;
    /**
     * 查询条件值
     */
    private Object queryParam;
    /**
     * 自定义的查询单元
     */
    private List<ConditionUnit> userConditionUnits;

    private QueryConditionBuilder() {

    }

    /**
     * 构建一个空的查询条件解析器
     */
    public static QueryConditionBuilder builder() {
        return new QueryConditionBuilder();
    }

    /**
     * 构建主查询部分
     *
     * @param selectSql 主查询条件部分
     */
    public QueryConditionBuilder select(String selectSql) {
        SailingAssert.hasText(selectSql, "主查询语句不能为空！");
        this.select = selectSql;
        return this;
    }

    /**
     * 构建主查询部分
     *
     * @param selectSql 主查询条件部分
     */
    public QueryConditionBuilder select(StringBuilder selectSql) {
        SailingAssert.notNull(selectSql, "主查询语句不能为空！");
        return select(selectSql.toString());
    }

    /**
     * 构建where条件部分
     *
     * @param whereBuilder where条件部分，示例：name='张三' and age=20
     */
    public QueryConditionBuilder where(StringBuilder whereBuilder) {
        SailingAssert.notNull(whereBuilder, "where语句不能为空！");
        return where(whereBuilder.toString());
    }

    /**
     * 构建where条件部分
     *
     * @param whereCondition 主查询条件部分
     */
    public QueryConditionBuilder where(String whereCondition) {
        SailingAssert.hasText(whereCondition, "where语句不能为空！");
        this.where = whereCondition;
        return this;
    }

    /**
     * 构建分页信息
     *
     * @param pageable 分页对象
     */
    public QueryConditionBuilder pageable(Pageable pageable) {
        this.pageable = pageable;
        return this;
    }

    /**
     * 构建排序信息
     *
     * @param orderBy 排序信息
     */
    public QueryConditionBuilder orderBy(String orderBy) {
        this.orderBy = orderBy;
        return this;
    }

    /**
     * 构建分组信息
     *
     * @param groupBy 分组信息
     */
    public QueryConditionBuilder groupBy(String groupBy) {
        this.groupBy = groupBy;
        return this;
    }

    /**
     * 构建查询参数对象
     *
     * @param queryParam 查询参数对象
     */
    public QueryConditionBuilder queryParam(Object queryParam) {
        SailingAssert.notNull(queryParam, "查询参数不能为空！");
        this.queryParam = queryParam;
        return this;
    }

    /**
     * 用户自定义的查询单元
     *
     * @param supplier 查询单元生产函数
     */
    public QueryConditionBuilder userConditions(Supplier<List<ConditionUnit>> supplier) {
        this.userConditionUnits = supplier.get();
        return this;
    }

    /**
     * 构建一个动态解析查询条件对象
     */
    public QueryCondition build() {
        final QueryConditionBuilder queryConditionBuilder = this;
        return new QueryConditionImpl() {

            @Override
            public Pageable getPageable() {
                return queryConditionBuilder.pageable;
            }

            @Override
            protected String getQuery() {
                String mainSql = queryConditionBuilder.select.trim();
                if (StringUtils.isEmpty(queryConditionBuilder.where)) {
                    mainSql += DEFAULT_WHERE_CONDITION;
                } else {
                    mainSql += WHERE_KEY + queryConditionBuilder.where.trim();
                }
                return mainSql;
            }

            @Override
            public Object getQueryConditionObj() {
                return queryConditionBuilder.queryParam;
            }

            @Override
            public String orderBy() {
                return queryConditionBuilder.orderBy;
            }

            @Override
            public String groupBy() {
                return queryConditionBuilder.groupBy;
            }

            @Override
            public List<ConditionUnit> userConditionUint() {
                return queryConditionBuilder.userConditionUnits;
            }

        };
    }

}
